require File.dirname(__FILE__) + '/../../../../test/test_helper'

class SettingsTest < ActiveSupport::TestCase
  
  def setup
    @key_name = 'some_key'
    Rails.cache.clear
  end
  
  ##############################
  # Validations                #
  ##############################
  test 'should require key' do
    setting = Settings.create(:key => nil)
    assert_not_nil setting.errors.on(:key)
  end
    
  ##############################
  # Proper Serialization       #
  ##############################
  test 'should serialize string correctly' do
    val = 'some string'
    setting = Settings.create(:key => @key_name, :value => val)
    setting.reload
    assert_equal val, setting.value
  end
  
  test 'should serialize boolen correctly' do
    val = true
    setting = Settings.create(:key => @key_name, :value => val)
    setting.reload
    assert_equal val, setting.value
  end
  
  test 'should serialize integer correctly' do
    val = 1
    setting = Settings.create(:key => @key_name, :value => val)
    setting.reload
    val = setting.value
    assert_equal val, val
    assert_equal 2, val*2
  end
  
  test 'should serialize float correctly' do
    val = 0.1
    setting = Settings.create(:key => @key_name, :value => val)
    setting.reload
    val = setting.value
    assert_equal val, val
    assert_equal 0.2, val*2
  end
  
  test 'should serialize nil correctly' do
    setting = Settings.create(:key => @key_name)
    setting.reload
    assert_equal nil, setting.value
  end
  
  ##############################
  # Hash Functionality         #
  ##############################
  test 'should retrieve key' do
    val = true
    Settings.create(:key => @key_name, :value => val)
    
    #key given as string
    setting = Settings[@key_name]
    assert_equal setting, val
    
    #key given as symbol
    setting = Settings[@key_name.to_sym]
    assert_equal setting, val
  end
  
  test 'should retrieve key immediatley after setting (when created with symbol)' do
    key = :with_key
    val = 'some val'
    Settings[key] = val
    assert_equal val, Settings[key]
  end
  
  test 'should set key' do
    val = true
    Settings[@key_name] = val
    setting = Settings.find_by_key(@key_name)
    assert_equal setting.value, val
  end
  
  test 'should return nil if key does not exist' do
    assert_nil Settings[:some_unknown_key]
  end
  
  test 'should remove existing key' do
    Settings[@key_name] = true
    Settings.remove @key_name
    assert_nil Settings[@key_name]
  end
  
  test 'should return nil when trying to remove non-existent key' do
    assert_nil Settings.remove :non_existent_key
  end
  
  test 'should not create setting with nil key' do
    assert_no_difference('Settings.count') do
      Settings[nil] = 'something'
    end
  end
     
  ##############################
  # Duplicate Handling         #
  ##############################
  test 'should not allow creation of duplicate keys' do
    val = true
    setting = Settings.create(:key => @key_name, :value => val)
    assert !setting.new_record?
    
    #Try to create duplicate key
    setting = Settings.create(:key => @key_name, :value => val)
    assert setting.new_record?
  end
  
  test 'should overwrite setting vs. creating a new one if existing key is specified' do
    val = true
    Settings[@key_name] = val
    assert_no_difference('Settings.count') do
      val = false
      setting = (Settings[@key_name] = val)
      assert_equal val, setting
    end
  end
  
  ##############################
  # Collections                #
  ##############################
  test 'should return all keys' do
    val = 'some val'
    keys = [:a_key, :b_key]
    keys.each {|k| Settings[k] = val}
    assert_equal keys, Settings.keys
  end
  
  ##############################
  # Cache                      #
  ##############################
  test 'should set cache' do
    cache_key = "settings/#{@key_name}"
    assert_nil Rails.cache.fetch(cache_key)
    Settings[@key_name] = 'some val'
    #Now fetch it so it will be cached
    Settings[@key_name]
    assert_not_nil Rails.cache.fetch(cache_key)
  end
  
  test 'should clear cache when updated' do
    cache_key = "settings/#{@key_name}"
    Settings[@key_name] = 'some val'
    #Now fetch it so it will be cached
    Settings[@key_name]
    Settings[@key_name] = 'other val'
    assert_nil Rails.cache.fetch(cache_key)
  end
  
  test 'should clear cache when destroyed' do
    cache_key = "settings/#{@key_name}"
    Settings[@key_name] = 'some val'
    #Now fetch it so it will be cached
    Settings[@key_name]
    Settings.remove @key_name
    assert_nil Rails.cache.fetch(cache_key)    
  end
  
  test 'should create cache for Settings.keys' do
    cache_key = "settings/settings.keys"
    #Create a key
    Settings[@key_name] = 'some val'
    #Call to set cache
    Settings.keys
    assert_not_nil Rails.cache.fetch(cache_key)
  end
  
  test 'should remove cache for Settings.keys whenever a new key is added' do
    cache_key = "settings/settings.keys"
    #Create a key
    Settings[@key_name] = 'some val'
    #Call to set cache
    Settings.keys
    assert_not_nil Rails.cache.fetch(cache_key)
    #Add a new key
    Settings[:another_key] = 'some other val'
    assert_nil Rails.cache.fetch(cache_key)
  end
  
  test 'should remove cache for Settings.keys whenever a key is updated' do
    cache_key = "settings/settings.keys"
    #Create a key
    Settings[@key_name] = 'some val'
    #Call to set cache
    Settings.keys
    assert_not_nil Rails.cache.fetch(cache_key)
    #Update a key
    setting = Settings.find_by_key(@key_name.to_s)
    setting.update_attribute(:key, 'another_key')
    assert_nil Rails.cache.fetch(cache_key)
  end
  
  test 'should remove cache for Settings.keys whenever a key is removed' do
    cache_key = "settings/settings.keys"
    #Create a key
    Settings[@key_name] = 'some val'
    #Call to set cache
    Settings.keys
    assert_not_nil Rails.cache.fetch(cache_key)
    #Update a key
    Settings.remove(@key_name)
    assert_nil Rails.cache.fetch(cache_key)
  end
end
